package srdb.migration.common;


import java.math.BigInteger;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import srdb.migration.MTKException;
import srdb.migration.schema.metadata.Column;
import srdb.migration.schema.metadata.ColumnList;
import srdb.migration.schema.metadata.Constraint;
import srdb.migration.schema.metadata.DBLink;
import srdb.migration.schema.metadata.DataType;
import srdb.migration.schema.metadata.Domain;
import srdb.migration.schema.metadata.Function;
import srdb.migration.schema.metadata.Grant;
import srdb.migration.schema.metadata.Group;
import srdb.migration.schema.metadata.Index;
import srdb.migration.schema.metadata.ObjectType;
import srdb.migration.schema.metadata.Package;
import srdb.migration.schema.metadata.Procedure;
import srdb.migration.schema.metadata.Role;
import srdb.migration.schema.metadata.Rule;
import srdb.migration.schema.metadata.Schema;
import srdb.migration.schema.metadata.Sequence;
import srdb.migration.schema.metadata.Synonym;
import srdb.migration.schema.metadata.Table;
import srdb.migration.schema.metadata.Trigger;
import srdb.migration.schema.metadata.User;
import srdb.migration.schema.metadata.View;
import srdb.migration.schema.metadata.DBLink.LINKTYPE;

public abstract class MTKTransformDDL {
	protected static BigInteger maxSeqenceValue = new BigInteger(
			"9223372036854775807");

	protected Map<String, String> customColTypeMapping = null;
	protected String defaultDateTime = null;

	private Hashtable<String, String> sourceToTargetMappings = null;

	public abstract String getCreateScript(Procedure paramProcedure);

	public abstract String getCreateScript(Function paramFunction);

	public abstract String getCreateScript(Synonym paramSynonym);

	public abstract String getCreateScript(Trigger paramTrigger);

	public abstract String getCreateScript(Constraint paramConstraint);

	public abstract String getCreateScript(Index paramIndex);

	public abstract String getCreateScript(Role paramRole);

	public abstract String getCreateScript(User paramUser);

	public abstract String getCreateScript(Grant paramGrant);

	public abstract String getCreateScript(Rule paramRule);

	public abstract String getCreateScript(Group paramGroup);

	public abstract String getCreateScript(Domain paramDomain);

	public abstract String getCreateScript(DataType paramDataType);

	public abstract String getCreateScriptPackageSpec(Package paramPackage);

	public abstract String getCreateScriptPackageBody(Package paramPackage);

	protected abstract String getColumnLine(Column paramColumn);

	public String getCreateScript(Schema schema) {
		return getCreateSchemaScript(schema.getName(true));
	}

	public String getCreateSchemaScript(String schemaName) {
		String sql = "CREATE SCHEMA " + schemaName + ";\n";
		return sql;
	}

	public String getDropSchemaScript(String schemaName) {
		String sql = "DROP SCHEMA " + schemaName + " CASCADE;\n";
		return sql;
	}

	public String getDropScript(Schema schema) {
		return getDropSchemaScript(schema.getName(true));
	}

	public String getCreateScript(Table table) throws MTKException {
		String sql = "CREATE UNLOGGED TABLE " + table.getName() + " (\n";

		if (table.getColumns() != null) {
			for (int i = 0; i < table.getColumns().size(); i++) {
				if (table.getColumns().get(i).getInhCount() == 0) {
					sql = sql + getColumnLine(table.getColumns().get(i));
					if (i < table.getColumns().size() - 1)
						sql = sql + ", ";
					sql = sql + "\n";
				}
			}
		}

		sql = sql + ")";
//		System.out.println(sql);
		return sql;
	}

	public String getCreateScript(View view) {
		String sql = "CREATE VIEW " + view.getName();
		String viewColumnList = view.getColumnAliasList();

		if (!viewColumnList.equals("")) {
			sql = sql + " (" + viewColumnList + ") ";
		}

		sql = sql + " AS \n" + view.getSQL() + "\n";

		return sql;
	}

	public String getCreateScript(Sequence sequence) {
		String sql = "CREATE SEQUENCE " + sequence.getName(true) + " \n";

		sql = sql + " MINVALUE " + sequence.getMinVal().toString() + " \n";

		if (maxSeqenceValue.compareTo(sequence.getMaxVal()) < 0)
			sql = sql + " MAXVALUE " + maxSeqenceValue.toString() + " \n";
		else {
			sql = sql + " MAXVALUE " + sequence.getMaxVal().toString() + " \n";
		}
		sql = sql + " START " + sequence.getLastNumber().toString() + " \n";
		sql = sql + " INCREMENT BY " + sequence.getIncrement().toString()
				+ "\n";

		if (sequence.getCacheSize() >= 1L) {
			sql = sql + " CACHE " + sequence.getCacheSize() + " \n";
		}
		if (sequence.isCycle()) {
			sql = sql + " CYCLE \n";
		}
		sql = sql + ";";
		return sql;
	}

	public String getCreateScript(ObjectType objectType) {
		return "";
	}

	protected String getIndent() {
		return "    ";
	}

	protected String stripDefaultClause(String header) {
		while (header.toUpperCase().contains(" DEFAULT")) {
			int startClause = 0;
			int endClause = 0;

			startClause = header.toUpperCase().indexOf(" DEFAULT");
			endClause = header.substring(startClause).indexOf(",");

			if (endClause < 0) {
				endClause = header.substring(startClause).indexOf(")");
			}
			if (endClause < 0) {
				endClause = header.substring(startClause).indexOf(";");
			}

			String testStr = header.substring(startClause, startClause
					+ endClause);
			if (testStr.contains("'")) {
				int nextEnd = 0;
				String tailStr = header.substring(startClause + endClause);
				int nextEnd1 = tailStr.indexOf(",");
				int nextEnd2 = tailStr.indexOf(")");
				if ((nextEnd1 < nextEnd2) && (nextEnd1 > 0))
					nextEnd = nextEnd1;
				else {
					nextEnd = nextEnd2;
				}
				endClause += nextEnd;
			}

			header = header.substring(0, startClause)
					+ header.substring(startClause + endClause);
		}

		return header;
	}

	protected String getColumnsComments(Table table) {
		return "";
	}

	protected String getTableComments(Table table) {
		return "";
	}

	public void setCustomColTypeMapping(Map<String, String> customColTypeMapping) {
		this.customColTypeMapping = customColTypeMapping;
	}

	protected String getCustomColType(String tableName, String colName) {
		if (this.customColTypeMapping == null) {
			return null;
		}

		String customColType = null;
		Iterator customColTypeMappingIter = this.customColTypeMapping.keySet()
				.iterator();
		String[] tableColName = null;

		while (customColTypeMappingIter.hasNext()) {
			String colNamePattern = (String) customColTypeMappingIter.next();

			if ((tableColName = colNamePattern.split("\\\\\\.")).length == 2) {
				if ((Pattern.compile(tableColName[0], 2).matcher(tableName)
						.matches())
						&& (Pattern.compile(tableColName[1], 2)
								.matcher(colName).matches())) {
					return (String) this.customColTypeMapping
							.get(colNamePattern);
				}
			} else if (Pattern.compile(colNamePattern, 2).matcher(colName)
					.matches()) {
				return (String) this.customColTypeMapping.get(colNamePattern);
			}
		}

		return customColType;
	}

	public String getDefaultDateTime() {
		return this.defaultDateTime;
	}

	public void setDefaultDateTime(String value) {
		this.defaultDateTime = value;
	}

	public String getCreateScript(DBLink link) {
		String sql = "CREATE " + link.getLinkType().toString();
		sql = sql + " DATABASE LINK " + link.getName() + " CONNECT TO "
				+ link.getUserName() + " IDENTIFIED BY " + link.getPassword()
				+ " USING '" + link.getHost() + "'";

		return sql;
	}

	public void setSourceToTargetNames(Hashtable<String, String> mappings) {
		this.sourceToTargetMappings = mappings;
	}

	public Hashtable<String, String> getSourceToTargetNames() {
		return this.sourceToTargetMappings;
	}

	protected String replaceSchemaName(String src, String origSchema,
			String newSchema) {
		StringBuffer newSrc = new StringBuffer();
		String schemaExp = "(\\s+|[.,])" + origSchema + "([.])" + ".*";
		for (int i = 0; i < src.length(); i++) {
			char c = src.charAt(i);
			switch (c) {
			case '\'':
				newSrc.append(c);
			case '"':
			}
			while ((i < src.length() - 1) && (src.charAt(i + 1) != '\'')) {
				i++;
				// newSrc.append(src.charAt(i));
				newSrc.append(c);
				continue;
			}

			while ((i < src.length() - 1) && (src.charAt(i + 1) != '"')) {
				i++;
				newSrc.append(src.charAt(i));
//				continue;

				String tmpStr = src.substring(i);
				Pattern p = Pattern.compile(schemaExp, 42);

				Matcher m = p.matcher(tmpStr);
				tmpStr = null;
				if (m.matches()) {
					String pre = m.group(1);
					String post = m.group(2);
					newSrc.append(pre);
					newSrc.append(newSchema);
					newSrc.append(post);
					i = i + (pre + origSchema + post).length() - 1;
				} else {
					newSrc.append(c);
				}
			}

		}
		return newSrc.toString();
	}

	protected String replaceNames(String src, Hashtable<String, String> mappings) {
		if ((mappings == null) || (mappings.size() == 0))
			return src;
		Enumeration keys = mappings.keys();
		while (keys.hasMoreElements()) {
			String key = (String) keys.nextElement();
			if (((String) mappings.get(key)).equalsIgnoreCase(key))
				continue;
			src = replaceSchemaName(src, key, (String) mappings.get(key));
		}
		return src;
	}
}

/*

 */